﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.IO.Ports;
using System.IO;
using System.Text;
using System.Configuration;
using System.Linq;

//TODO，解析各测量仪器数据，体温数据是一次性数据，血压可以连续测量但是测量数据是离散的，心电和血氧是连续数据；需要获取测量时间，对心电和血氧来说，有开始时间和结束时间
//TODO，需要通过命令控制测量仪器工作
//TODO，如何去掉冗余的数据
//TODO，如何查找到社区版对应的COM接口
//TODO，测量数据通过事件方式传送给外部程序
//TODO，解析和处理波形附加包
namespace com.jwxcd.CommunityDriver
{
    /// <summary>
    /// 社区版的驱动程序
    /// </summary>
    public class IytongDriver
    {
        /// <summary>
        /// 每次收到测量数据将会触发此事件
        /// </summary>
        public event EventHandler<MeasureEventArgs> onMeausreEvent;

        /// <summary>
        /// 与测量设备连接成功将会触发此事件
        /// </summary>
        public event EventHandler onConnectedEvent;

        /// <summary>
        /// 与测量设备断开连接将会触发此事件
        /// </summary>
        public event EventHandler onDisconnectedEvent;

        /// <summary>
        /// 通知事件
        /// </summary>
        public event EventHandler<MeasureNoticeArgs> onNoticeEvent;


        private GlobalConfig g_cfg;

        public bool IsMeterTypeEnd
        {
            get
            {
                return g_cfg.MeterType == MeterType.End;
            }
        }


        public IytongDriver()
        {
            this.g_cfg = GlobalConfig.getGlobalConfigInstance();
        }

        /// <summary>
        /// 与指定的COM端口建立连接，并确定这个COM端口是否是IYTong社区版对应的COM端口
        /// </summary>
        /// <param name="comPort">指定的COM端口</param>
        private void connect2Port(Object comPort)
        {
            SerialPort _serialPort = (SerialPort)comPort;

            //if (_serialPort.PortName == "COM3")
            //    return;

            bool showInfo = true;

            //握手失败次数
            int iErrHandCount = 0;
            //连接超时次数
            int iTimeoutCount = 0;
            //连接未成功次数
            int iConFailCount = 0;

            while (!this.g_cfg.IsConnected)
            {
                try
                {
                    //测试启动命令
                    byte[] startCmd = new byte[2];
                    startCmd[0] = 0x55;
                    startCmd[1] = 0xaa;
                    _serialPort.Write(startCmd, 0, 2);

                    String rs = _serialPort.ReadByte().ToString("X");
                    if (rs.Equals("1B", StringComparison.CurrentCulture))
                    {
                        String header = _serialPort.ReadByte().ToString("X");

                        //握手成功
                        if (header.Equals("3F", StringComparison.CurrentCulture) || header.Equals("A1", StringComparison.CurrentCulture) || header.Equals("A2", StringComparison.CurrentCulture))
                        {
                            //发送菜单参数包
                            //byte[] menu = { 0x0b, 0x40, 0x02, 0xb1, 0xfa, 0xc2, 0x3c, 0xc8, 0x32, 0x28, 0x0a, 0x64, 0x55, 0x82, 0x32, 0x5a, 0x28, 0x6e, 0x28, 0x6e, 0x46, 0x6e, 0x46, 0x00, 0x01, 0x04, 0x07, 0x46, 0x0a, 0x0a, 0x00, 0x00 };
                            //_serialPort.Write(menu, 0, menu.Length);

                            //修改全局配置参数
                            this.g_cfg.SerialPort = _serialPort;
                            this.g_cfg.IsConnected = true;
                            this.g_cfg.MeterType = MeterType.Init;

                            //触发连结成功的事件
                            OnConnected(new EventArgs());

                            //并启动真正的端口侦听线程
                            Thread readDataFromDevice = new Thread(new ThreadStart(readMeasureData));
                            //启动线程每秒钟与测量设备建立一次对话                            
                            Thread handshakeThread = new Thread(new ThreadStart(handshake));

                            threadList.Add(readDataFromDevice);
                            threadList.Add(handshakeThread);

                            readDataFromDevice.Start();
                            handshakeThread.Start();


                            return;
                        }
                        else
                        {
                            if (++iErrHandCount > 10)
                            {
                                //握手失败10次以上则关闭
                                if (!this.g_cfg.IsConnected)
                                {
                                    if (_serialPort.IsOpen)
                                    {
                                        //onNoticeEvent(this, new MeasureNoticeArgs(string.Format("端口：{0} 退出 握手失败", _serialPort.PortName)));
                                        _serialPort.Close();
                                    }
                                }
                                //this.g_cfg.isExit = true;
                                return;
                            }
                        }
                    }
                    
                }
                catch (TimeoutException ) //超时，设备插入但未开机
                {
                    iTimeoutCount++;
                    if ((iTimeoutCount * g_cfg.ReadTimeout) == 5000)
                    {
                        //if (showInfo)
                        //    onNoticeEvent(this, new MeasureNoticeArgs("设备未开机！"));
                        showInfo = false;
                    }
                    if (iTimeoutCount * g_cfg.ReadTimeout > 60000)
                    {
                        if (!this.g_cfg.IsConnected)
                        {
                            if (_serialPort.IsOpen)
                            {
                                //onNoticeEvent(this, new MeasureNoticeArgs(string.Format("端口：{0} 退出 连接超时", _serialPort.PortName)));
                                _serialPort.Close();
                            }
                        }
                        //this.g_cfg.isExit = true;
                        return;
                    }
                    else
                    {
                        //是否用户发送退出指令
                        if (this.g_cfg.isExit)
                        {
                            if (_serialPort.IsOpen)
                            {
                                //onNoticeEvent(this, new MeasureNoticeArgs(string.Format("端口：{0} 退出 用户指令 ", _serialPort.PortName)));
                                
                                _serialPort.Close();
                                
                            }
                            return;
                           
                        }
                        else
                        {
                            continue;
                        }
                    }
                }

                //连接成功的时候其他端口退出
                if (this.g_cfg.IsConnected)
                {
                    if (_serialPort.IsOpen)
                    {
                        //onNoticeEvent(this, new MeasureNoticeArgs(string.Format("端口：{0} 退出 设备已经连接 ", _serialPort.PortName)));
                        _serialPort.Close();
                    }
                    return;
                }

                //是否用户发送退出指令
                if (this.g_cfg.isExit)
                {
                    if (_serialPort.IsOpen)
                    {
                        //onNoticeEvent(this, new MeasureNoticeArgs(string.Format("端口：{0} 退出 用户指令 ", _serialPort.PortName)));
                        _serialPort.Close();
                    }
                    return;
                }

                Thread.Sleep(10);
                if (++iConFailCount*10 > this.g_cfg.ConnectTimeout)
                {
                    //onNoticeEvent(this, new MeasureNoticeArgs(string.Format("端口：{0} 没有设备 ",_serialPort.PortName)));
                    //onNoticeEvent(this, new MeasureNoticeArgs(string.Format("如果设备没有连接，请连接设备并重新进入此页面！ ", _serialPort.PortName)));
                    if (_serialPort.IsOpen)
                    {
                        //onNoticeEvent(this, new MeasureNoticeArgs(string.Format("端口：{0} 退出 没有设备", _serialPort.PortName)));
                        _serialPort.Close();
                    }
                    return;
                }
            }

            //连接成功的时候其他端口退出
            if (this.g_cfg.IsConnected)
            {
                if (_serialPort.IsOpen)
                {
                    //onNoticeEvent(this, new MeasureNoticeArgs(string.Format("端口：{0} 在外层退出 设备已经连接 ", _serialPort.PortName)));
                    _serialPort.Close();
                }
                return;
            }

        }

        private void writeCmd(SerialPort port,string cmdAlias)
        {
            string cmdStr = ConfigurationManager.AppSettings[cmdAlias];
            if (!string.IsNullOrEmpty(cmdStr))
            {
                var cmdList = cmdStr.Split(',').ToList().Select(c => Convert.ToByte(c.Trim(), 16)).ToArray();
                if (cmdList != null)
                {
                    port.Write(cmdList, 0, cmdList.Length);
                    
                    using (var sw = File.AppendText("./cmd.txt"))
                    {
                        sw.WriteLine(string.Format("{0} send cmd: {1} {2}",cmdAlias, string.Join(",", cmdList.Select(c => c.ToString("x"))), DateTime.Now));
                        sw.Flush();
                    }
                }
            }
        }

        /// <summary>
        /// 需要与测量设备每秒钟建立一次对话
        /// </summary>
        private void handshake()
        {
            while (this.g_cfg.IsConnected)
            {
                Thread.Sleep(500);
                SerialPort _serialPort = this.g_cfg.SerialPort;

                //测试启动命令
                byte[] startCmd = new byte[2];
                startCmd[0] = 0x55;
                startCmd[1] = 0xaa;

                if (this.g_cfg.IsConnected && _serialPort.IsOpen)
                {
                    _serialPort.Write(startCmd, 0, 2);

                    string cmdStr = string.Empty;
                    byte[] cmdList = null;
                    //控制设备
                    switch (this.g_cfg.MeterType)
                    {
                        case MeterType.StartBP:
                            writeCmd(_serialPort, "StartBP");
                           
                            Thread.Sleep(500);
                            this.g_cfg.MeterType = MeterType.End;
                            continue;
                            //break;
                        case MeterType.EndBP:
                            writeCmd(_serialPort, "EndBP");
                            this.g_cfg.MeterType = MeterType.End;
                            Thread.Sleep(500);
                            continue;
                            //break;
                        case MeterType.TempAttention:
                            writeCmd(_serialPort, "TempAttention");
                            
                            Thread.Sleep(500);
                            this.g_cfg.MeterType = MeterType.TempStart;
                            continue;
                            //break;
                        case MeterType.TempStart:
                            writeCmd(_serialPort, "TempStart");
                            this.g_cfg.MeterType = MeterType.End;
                            Thread.Sleep(500);
                            continue;
                            //break;
                        case MeterType.BGAttention:
                            writeCmd(_serialPort, "BGAttention");
                            
                           
                            this.g_cfg.MeterType = MeterType.End;
                            Thread.Sleep(500);
                            //this.g_cfg.MeterType = MeterType.BGBoxCodeConfirm;
                            continue;
                            //break;
                        case MeterType.BGBoxCodeConfirm:
                            cmdStr = ConfigurationManager.AppSettings["BGBoxCodeConfirm"];
                            if (!string.IsNullOrEmpty(cmdStr))
                                cmdList = cmdStr.Split(',').ToList().Select(c => Convert.ToByte(c.Trim(), 16)).ToArray();

                            if (cmdList != null)
                            {
                                int temp = boxCode;
                                int cknum = cmdList[5] + temp;
                                cknum = cknum - cknum / 256 * 256;
                                byte cs = Convert.ToByte(cknum);
                                byte bc = Convert.ToByte(temp);
                                cmdList[5] = cs;
                                cmdList[8] = bc;
                                boxCode = 0x00;
                                _serialPort.Write(cmdList, 0, cmdList.Length);
                                Thread.Sleep(500);

                                using (var sw = File.AppendText("./cmd.txt"))
                                {
                                    sw.WriteLine(string.Format("send cmd: {0} {1}", string.Join(",", cmdList.Select(c => c.ToString("x"))), DateTime.Now));
                                    sw.Flush();
                                }
                            }
                            this.g_cfg.MeterType = MeterType.End;
                            Thread.Sleep(500);
                            continue;
                            //break;
                        default:
                            break;
                    }
                   
                    
                }

                Thread.Sleep(500);
            }
        }

        private int boxCode = 0x00;

        /// <summary>
        /// 触发onConnectedEvent
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnConnected(EventArgs e)
        {
            using (var sw = File.AppendText("./log.txt"))
            {
                sw.WriteLine(string.Format("device connected {0}", DateTime.Now));
                sw.Flush();
            }

            // Make a temporary copy of the event to avoid possibility of
            // a race condition if the last subscriber unsubscribes
            // immediately after the null check and before the event is raised.
            EventHandler handler = onConnectedEvent;
            if (handler != null)
            {
                handler(this, e);
            }
        }


        /// <summary>
        /// 侦听设备端口，一旦获取到数据，触发onMeausreEvent事件
        /// </summary>
        private void readMeasureData()
        {
            SerialPort sp = this.g_cfg.SerialPort;
            String _bValue = "";

            //StreamWriter sw = new StreamWriter("C:\\test.txt");
            //StringBuilder sb = new StringBuilder();


            while (this.g_cfg.IsConnected)
            {
                MeasureValue mv = new MeasureValue();

                try
                {
                    #region test
                    if (_bValue.Equals("1B", StringComparison.CurrentCulture))
                    {
                        String header = sp.ReadByte().ToString("X");

                        //sb = new StringBuilder();

                        //握手成功
                        if (header.Equals("3F", StringComparison.CurrentCulture))
                        {

                            byte[] hs = new byte[32];
                            hs[0] = 0x0b;
                            hs[1] = 0x40;
                            for (int count = 2; count < 32; count++)
                            {
                                hs[count] = 0x00;
                            }
                            sp.Write(hs, 0, 32);


                        }
                        //如果是体温或者血糖数据，按照TVE的B820 UART协议进行解析
                        else if (header.Equals("AF", StringComparison.CurrentCulture))
                        {
                            //读出FF
                            sp.ReadByte();
                            //读出FE
                            sp.ReadByte();
                            //读出Length of Msg
                            sp.ReadByte();
                            //读出CheckSum
                            sp.ReadByte();

                            //读出设备ID
                            String deviceID = sp.ReadByte().ToString("X");

                            //表明当前是耳温计
                            if (deviceID.Equals("22", StringComparison.CurrentCulture))
                            {
                                String command = sp.ReadByte().ToString("X");
                                using (var sw = File.AppendText("./log.txt"))
                                {
                                    sw.WriteLine(string.Format("temp cmd {0} {1}", DateTime.Now, command));
                                    sw.Flush();
                                }

                                //result
                                if (command.Equals("65", StringComparison.CurrentCulture))
                                {
                                    //返回测试结果，解析规则：(第一字节+第二字节*256)/10
                                    float _fValue = (float)Convert.ToInt32(sp.ReadByte().ToString("X"), 16);
                                    float _lValue = (float)Convert.ToInt32(sp.ReadByte().ToString("X"), 16);
                                    float tempValue = (_fValue + _lValue * 256) / 10;
                                    mv.DataType = 0;
                                    mv.Temperature = tempValue;
                                    //sw.WriteLine("体温数据是：" + tempValue + "");
                                    //sw.Flush();

                                }

                                ////Device ready
                                //if (command.Equals("61", StringComparison.CurrentCulture))
                                //{
                                //    this.SetDeviceState(MeterType.TempAttention);
                                //    using (var sw = File.AppendText("./log.txt"))
                                //    {
                                //        sw.WriteLine(string.Format("temp attention {0}", DateTime.Now));
                                //        sw.Flush();
                                //    }
                                //}
                                ////start
                                //if (command.Equals("62", StringComparison.CurrentCulture))
                                //{
                                //    this.SetDeviceState(MeterType.TempStart);
                                //    using (var sw = File.AppendText("./log.txt"))
                                //    {
                                //        sw.WriteLine(string.Format("temp recv 'request to start' and send 'start' {0}",DateTime.Now));
                                //        sw.Flush();
                                //    }
                                //}

                                //ErrCode
                                if (command.Equals("66", StringComparison.CurrentCulture))
                                {
                                    int errCode = sp.ReadByte();
                                    using (var sw = File.AppendText("./log.txt"))
                                    {
                                        sw.WriteLine(string.Format("temp err {0} : {1} {2}", DateTime.Now, command, errCode.ToString("X")));
                                        sw.Flush();
                                    }
                                }

                               
                            }
                            //表明当前是血糖
                            else if (deviceID.Equals("25", StringComparison.CurrentCulture))
                            {
                                String command = sp.ReadByte().ToString("X");
                                using (var sw = File.AppendText("./log.txt"))
                                {
                                    sw.WriteLine(string.Format("bg cmd {0} {1}", DateTime.Now, command));
                                    sw.Flush();
                                }
                                //Result
                                if (command.Equals("75", StringComparison.CurrentCulture))
                                {
                                    float _fValue = (float)Convert.ToInt32(sp.ReadByte().ToString("X"), 16);
                                    float _lValue = (float)Convert.ToInt32(sp.ReadByte().ToString("X"), 16);
                                    float glucose_Value = (_fValue + _lValue) / 10;
                                    mv.Glucose = glucose_Value;

                                    using (var sw = File.AppendText("./log.txt"))
                                    {
                                        sw.WriteLine(string.Format("bg value {0} : {1} {2} {3}", DateTime.Now, _fValue, _lValue, glucose_Value));
                                        sw.Flush();
                                    }
                                }

                                //BG Device ready
                                //if (command.Equals("71", StringComparison.CurrentCulture))
                                //{
                                //    using (var sw = File.AppendText("./log.txt"))
                                //    {
                                //        sw.WriteLine(string.Format("bg attention {0}", DateTime.Now));
                                //        sw.Flush();
                                //    }
                                //    this.SetDeviceState(MeterType.BGAttention);
                                //}
                                //BoxCode
                                if (command.Equals("73", StringComparison.CurrentCulture))
                                {
                                    int bc = sp.ReadByte();
                                    using (var sw = File.AppendText("./log.txt"))
                                    {
                                        sw.WriteLine(string.Format("box code {0} : {1} {2}", DateTime.Now, command, bc.ToString("X")));
                                        sw.Flush();
                                    }
                                    boxCode = bc;
                                    this.SetDeviceState(MeterType.BGBoxCodeConfirm);
                                }
                                
                                //ErrCode
                                if (command.Equals("76", StringComparison.CurrentCulture))
                                {
                                    int errCode = sp.ReadByte();
                                    using (var sw = File.AppendText("./log.txt"))
                                    {
                                        sw.WriteLine(string.Format("bg err {0} : {1} {2}", DateTime.Now, command, errCode.ToString("X")));
                                        sw.Flush();
                                    }
                                }

                             
                            }
                        }
                        else if (header.Equals("A1", StringComparison.CurrentCulture))
                        {
                            //图形数据包                            

                            //sb.Append("1B A1");
                            mv.DataType = 1;

                            List<int> ecgDatas = new List<int>();
                            int value = 0;
                            for (int count = 0; count < 10; count++)
                            {
                                value = sp.ReadByte();
                                ecgDatas.Add(value);
                                //sb.Append(" " + value);
                            }
                            mv.ECG = ecgDatas;

                            List<int> spO2Datas = new List<int>();
                            for (int count = 0; count < 5; count++)
                            {
                                value = sp.ReadByte();
                                spO2Datas.Add(value);
                                //sb.Append(" " + value);
                            }
                            mv.SpO2 = spO2Datas;


                            value = sp.ReadByte();
                            _bValue = value.ToString("X");
                            while (!(_bValue.Equals("1B", StringComparison.CurrentCulture)) && g_cfg.IsConnected)
                            {

                                //sb.Append(" " + value);
                                value = sp.ReadByte();
                                _bValue = value.ToString("X");
                            }

                            //sw.WriteLine(sb.ToString());
                            //sw.Flush();

                        }
                        else if (header.Equals("A2", StringComparison.CurrentCulture))
                        {
                            //生理参数包
                            //sb.Append("1B A2");

                            mv.DataType = 0;

                            //心率值
                            mv.HR_Value = sp.ReadByte();
                            //血氧饱和度
                            mv.SpO2_value = sp.ReadByte();
                            //血氧脉搏值
                            mv.Pulse = sp.ReadByte();

                            //呼吸率
                            sp.ReadByte();
                            //体温1
                            sp.ReadByte();
                            //体温2
                            sp.ReadByte();
                            //有无创血压标识
                            sp.ReadByte();

                            //收缩压
                            mv.SBP = sp.ReadByte();
                            //舒张压
                            mv.DBP = sp.ReadByte();
                            //平均压
                            mv.Map = sp.ReadByte();

                            //无创血压脉率值
                            mv.PressurePulse = sp.ReadByte();
                            //无定义
                            sp.ReadByte();
                            //床旁机报警状态
                            sp.ReadByte();
                            //无定义
                            sp.ReadByte();
                            //无定义
                            sp.ReadByte();

                            //无创压袖带压
                            mv.NIBP = sp.ReadByte();

                            int value = sp.ReadByte();
                            _bValue = value.ToString("X");
                            while (!(_bValue.Equals("1B", StringComparison.CurrentCulture)) && g_cfg.IsConnected)
                            {
                                //sb.Append(" " + value);
                                value = sp.ReadByte();
                                _bValue = value.ToString("X");
                            }
                            //sw.WriteLine(sb.ToString());
                            //sw.Flush();
                        }
                        else if (header.Equals("A7", StringComparison.CurrentCulture))
                        {
                            /*
                            //波形附件包
                            //sb.Append("1B A7");
                            mv.DataType = 1;

                            //心电数据个数
                            int ecg_count = sp.ReadByte();
                            //血氧波形数据个数
                            int spo2_count = sp.ReadByte();
                            //呼吸波形数据个数
                            sp.ReadByte();
                            //有创1波形数据个数
                            sp.ReadByte();
                            //有创2波形数据个数
                            sp.ReadByte();
                            //呼吸波形数据个数
                            mv.Pulse = sp.ReadByte();

                            List<int> ecg = new List<int>();
                            //循环读取心电数据
                            for (int count = 0; count < ecg_count; count++)
                            {
                                ecg.Add(sp.ReadByte());
                            }
                            mv.ECG = ecg;

                            List<int> spo2 = new List<int>();
                            //循环读取血氧数据
                            for (int count = 0; count < spo2_count; count++)
                            {
                                spo2.Add(sp.ReadByte());
                            }
                            mv.SpO2 = spo2;

                            int value = sp.ReadByte();
                            _bValue = value.ToString("X");
                            while (!(_bValue.Equals("1B", StringComparison.CurrentCulture)) && g_cfg.IsConnected)
                            {
                                //sb.Append(" " + value);
                                value = sp.ReadByte();
                                _bValue = value.ToString("X");
                            }

                            //sw.WriteLine(sb.ToString());
                            //sw.Flush();
                            */
                        }
                        else if (header.Equals("A5", StringComparison.CurrentCulture))
                        {
                            //多导心电数据包
                            /*
                            sb.Append("1B A5");
                            _bValue = sp.ReadByte().ToString("X");
                            while (!(_bValue.Equals("1B", StringComparison.CurrentCulture)))
                            {
                                sb.Append(" " + _bValue);
                                _bValue = sp.ReadByte().ToString("X");
                            }

                            sw.WriteLine(sb.ToString());
                            sw.Flush();
                             * */
                        }

                    }
                    else
                    {
                        _bValue = sp.ReadByte().ToString("X");
                    }

                    
                    #endregion
                }
                catch (TimeoutException)
                {
                    
                }

                //在while的每次结束判断端口是否应该关闭
                //如果是则关闭端口并跳出
                if (!this.g_cfg.IsConnected )
                {
                    if (sp.IsOpen)
                    {
                        //onNoticeEvent(this, new MeasureNoticeArgs(string.Format("端口：{0} 在测试完成后退出 ", sp.PortName)));
                        sp.Close();
                    }
                    OnDisConnected(new EventArgs());
                    return;
                }

                //用户退出指令
                if (this.g_cfg.isExit)
                {
                    if (sp.IsOpen)
                    {
                        
                        sp.Close();
                    }
                    //onNoticeEvent(this, new MeasureNoticeArgs(string.Format("端口：{0} 在用户发送退出指令成后退出 ", sp.PortName)));
                    OnDisConnected(new EventArgs());
                    return;

                }

                OnMeausre(new MeasureEventArgs(mv));
            }

           
        }

        /// <summary>
        /// 触发onMeausreEvent
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnMeausre(MeasureEventArgs e)
        {
            EventHandler<MeasureEventArgs> handler = onMeausreEvent;
            if (handler != null)
            {
                handler(this, e);
            }
        }


        private List<Thread> threadList = new List<Thread>();
        private List<SerialPort> portList = new List<SerialPort>();

        /// <summary>
        /// 与硬件建立连接，连接成功将会触发onConnected事件
        /// </summary>
        public void connect()
        {
            //singleton 需要重新初始化为false
            this.g_cfg.isExit = false;
            this.g_cfg.IsConnected = false;
            this.g_cfg.SerialPort = null;

            String[] availablePorts = SerialPort.GetPortNames();
            
            foreach (String portName in availablePorts)
            {
                if (this.g_cfg.IsConnected)
                    break;

                SerialPort _serialPort = new SerialPort();
                _serialPort.PortName = portName;
                _serialPort.BaudRate = 19200;
                _serialPort.Parity = Parity.None;
                _serialPort.DataBits = 8;
                _serialPort.StopBits = StopBits.One;
                _serialPort.Handshake = Handshake.None;

                _serialPort.Encoding = System.Text.ASCIIEncoding.ASCII;

                // Set the read/write timeouts
                _serialPort.ReadTimeout = g_cfg.ReadTimeout;
                _serialPort.WriteTimeout = g_cfg.WriteTimeout;

                Thread findPort = new Thread(new ParameterizedThreadStart(connect2Port));
                
                findPort.Name = portName;
                //findPort.SetApartmentState( ApartmentState.STA);
                if (_serialPort.IsOpen)
                    _serialPort.Close();

                for (int i = 0; i < 100; i++)
                {
                    try
                    {
                        _serialPort.Open();
                        break;
                    }
                    catch(Exception e)
                    {
                        Thread.Sleep(20);
                        if (i == 99)
                        {
                            throw e;
                        }
                    }
                }
                _serialPort.DiscardInBuffer();
                _serialPort.DiscardOutBuffer();

                threadList.Add(findPort);
                portList.Add(_serialPort);

                findPort.Start(_serialPort);

                //this.g_cfg.addSerialPorts(_serialPort);
            }
        }

        /// <summary>
        /// 触发onDisconnectedEvent
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnDisConnected(EventArgs e)
        {
            using (var sw = File.AppendText("./log.txt"))
            {
                sw.WriteLine(string.Format("device disconnected {0}", DateTime.Now));
                sw.Flush();
            }

            EventHandler handler = onDisconnectedEvent;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        /// <summary>
        /// 断开与测量设备的连接，并触发onDisconnectedEvent
        /// </summary>
        public void disConnect()
        {
            //this.g_cfg.SerialPort.Close();
            for (int i = 0; i < 50; i++)
            {
                if (g_cfg.MeterType == MeterType.End)
                {
                    break;
                }
                Thread.Sleep(10);
            }


            this.g_cfg.isExit = true;
            this.g_cfg.IsConnected = false;


            for (int i=0;i <50 ;i++ )
            {
                if (g_cfg.SerialPort != null)
                {

                    if (!g_cfg.SerialPort.IsOpen)
                    {
                        //OnDisConnected(new EventArgs());
                        return;
                    }

                }
                else
                {
                    if (this.g_cfg.isExit)
                    {
                        break;
                    }
                }
                Thread.Sleep(10);
            }

            foreach (var i in threadList)
            {
                if (i.ThreadState != ThreadState.Stopped)
                    i.Abort();
            }
            if (!IsMeterTypeEnd)
                SetDeviceState(MeterType.End);
            foreach (var i in portList)
            {
                if (i.IsOpen)
                    i.Close();
            }
            OnDisConnected(new EventArgs());
            
        }


        public void SetDeviceState(MeterType type)
        {
            this.g_cfg.MeterType = type;
        }
    }

    /// <summary>
    /// 这是Driver所需的全局配置的类，采用Singleton模式
    /// </summary>
    class GlobalConfig
    {
        private volatile static GlobalConfig cfg;
        //private volatile List<SerialPort> serialPorts;
        private static object portSync = new Object();
        private static object statusSync = new Object();

        public int ReadTimeout
        {
            get
            {
                return 200;
            }
        }

        public int WriteTimeout
        {
            get
            {
                return 200;
            }
        }

        public int ConnectTimeout
        {
            get
            {
                return 5000;
            }
        }

        public MeterType MeterType { get; set; }

        /// <summary>
        /// 用户退出指令
        /// </summary>
        public bool isExit { get; set; }

        /// <summary>
        /// 爱意通测量设备所用的端口号
        /// </summary>
        private SerialPort _serialPort = null;

        public SerialPort SerialPort
        {
            get
            {
                lock (portSync)
                {
                    return _serialPort;
                }
            }
            set
            {
                lock (portSync)
                {
                    _serialPort = value;
                    //将设备端口从端口列表中移除
                    //serialPorts.Remove(value);
                }
            }
        }

        private bool isConnected = false;
        /// <summary>
        /// 爱意通测量设备是否连结成功
        /// </summary>
        public bool IsConnected
        {
            get
            {
                lock (statusSync)
                { return isConnected; }
            }
            set
            {
                lock (statusSync)
                {
                    isConnected = value;
                    //断开其他的COM端口
                    //foreach (SerialPort sp in serialPorts)
                    //{
                    //    sp.Close();
                    //}
                }
            }
        }
        /// <summary>
        /// 把所有的端口都加入端口列表
        /// </summary>
        /// <param name="serialPort"></param>
        private void addSerialPorts(SerialPort serialPort)
        {
            //this.serialPorts.Add(serialPort);
        }

        private GlobalConfig()
        {
            //this.serialPorts = new List<SerialPort>();
        }
        /// <summary>
        /// 采用singleton模式，保证只有一个实例运行
        /// </summary>
        /// <returns></returns>
        public static GlobalConfig getGlobalConfigInstance()
        {
            if (cfg == null)
                lock (portSync)
                {
                    cfg = new GlobalConfig();
                }

            return cfg;
        }
    }

    public enum MeterType
    {
        Init,
        End,
        StartBP,
        EndBP,
        TempAttention,
        TempStart,
        BGAttention,
        BGBoxCodeConfirm
    }
}
